package com.sky.service.impl;

import cn.mybatis.mp.core.mybatis.mapper.context.Pager;
import cn.mybatis.mp.core.sql.executor.chain.QueryChain;
import com.sky.dto.PageQueryDTO;
import com.sky.entity.AdminRoleAssignments;
import com.sky.entity.AdminRolePermissions;
import com.sky.entity.AdminRoles;
import com.sky.entity.AdminPermissions;
import com.sky.exception.BaseException;
import com.sky.mapper.AdminRoleAssignmentsMapper;
import com.sky.mapper.AdminRolePermissionsMapper;
import com.sky.mapper.AdminRolesMapper;
import com.sky.mapper.AdminPermissionsMapper;
import com.sky.service.AdminRoleService;
import com.sky.vo.AdminRoleVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import com.sky.constant.MessageConstant;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 管理员角色服务实现类
 * 实现了AdminRoleService接口定义的所有方法
 * 主要功能：
 * 1. 角色的增删改查管理
 * 2. 角色权限的分配和管理
 * 3. 管理员与角色的关联管理
 * 4. 角色相关的查询和验证
 *
 * 说明：
 * - 所有涉及多表操作的方法都使用@Transactional注解确保事务一致性
 * - 使用Mybatis-mp的查询方式实现数据库操作
 * - 包含完整的参数验证和错误处理
 */
@Service
@Slf4j
public class AdminRoleServiceImpl implements AdminRoleService {

    @Autowired
    private AdminRolesMapper adminRolesMapper;

    @Autowired
    private AdminRolePermissionsMapper adminRolePermissionsMapper;

    @Autowired
    private AdminRoleAssignmentsMapper adminRoleAssignmentsMapper;

    @Autowired
    private AdminPermissionsMapper adminPermissionsMapper;

    /**
     * 获取所有角色列表
     * 直接查询角色表获取所有记录
     *
     * @return 所有角色的列表
     */
    @Override
    public List<AdminRoles> getAllRoles() {
        return QueryChain.of(adminRolesMapper).list();
    }

    /**
     * 获取所有权限列表
     * 直接查询权限表获取所有记录
     *
     * @return 所有权限的列表
     */
    @Override
    public List<AdminPermissions> getAllPermissions() {
        return QueryChain.of(adminPermissionsMapper)
                .orderBy(AdminPermissions::getPermissionId)
                .list();
    }

    /**
     * 创建新角色
     * 实现步骤：
     * 1. 检查角色名唯一性
     * 2. 保存角色基本信息
     * 3. 建立角色与权限的关联关系
     *
     * 说明：
     * - 角色名不允许重复
     * - 支持同时设置角色权限
     * - 使用事务确保数据一致性
     *
     * @param role 角色信息对象
     * @param permissionIds 权限ID列表
     * @throws BaseException 当角色名已存在时
     */
    @Override
    @Transactional
    public void createRole(AdminRoles role, List<Integer> permissionIds) {
        // 检查角色名是否已存在
        AdminRoles existingRole = adminRolesMapper.get(where -> {
            where.eq(AdminRoles::getRoleName, role.getRoleName());
        });
        if (existingRole != null) {
            throw new BaseException(MessageConstant.ROLE_NAME_EXISTS);
        }

        // 保存角色信息
        adminRolesMapper.save(role);

        AdminRoles adminRoles = QueryChain.of(adminRolesMapper)
                .eq(AdminRoles::getRoleName,role.getRoleName())
                .get();

        // 保存角色权限关联
        if (permissionIds != null && !permissionIds.isEmpty()) {
            for (Integer permissionId : permissionIds) {
                AdminRolePermissions rolePermission = new AdminRolePermissions();
                rolePermission.setRoleId(adminRoles.getRoleId());
                rolePermission.setPermissionId(permissionId);
                adminRolePermissionsMapper.save(rolePermission);
            }
        }
    }

    /**
     * 更新角色信息
     * 实现步骤：
     * 1. 验证角色存在性
     * 2. 检查新角色名唯一性（如果修改了角色名）
     * 3. 更新角色基本信息
     * 4. 重建角色权限关联
     *
     * 说明：
     * - 如果未提供权限列表，则不修改权限
     * - 如果提供了权限列表，则完全覆盖原有权限
     * - 修改角色名时会检查是否与其他角色冲突
     *
     * @param role 角色信息对象
     * @param permissionIds 权限ID列表
     * @throws BaseException 当角色不存在或新角色名已存在时
     */
    @Override
    @Transactional
    public void updateRole(AdminRoles role, List<Integer> permissionIds) {
        // 检查角色是否存在
        AdminRoles existingRole = adminRolesMapper.get(where -> {
            where.eq(AdminRoles::getRoleId, role.getRoleId());
        });
        if (existingRole == null) {
            throw new BaseException(MessageConstant.ROLE_NOT_FOUND);
        }

        // 如果修改了角色名，检查新名称是否已存在
        if (!existingRole.getRoleName().equals(role.getRoleName())) {
            AdminRoles roleWithSameName = adminRolesMapper.get(where -> {
                where.eq(AdminRoles::getRoleName, role.getRoleName());
            });
            if (roleWithSameName != null) {
                throw new BaseException(MessageConstant.ROLE_NAME_EXISTS);
            }
        }

        // 更新角色信息
        adminRolesMapper.update(role);

        // 更新角色权限关联
        if (permissionIds != null) {
            // 删除原有权限关联
            adminRolePermissionsMapper.delete(where -> {
                where.eq(AdminRolePermissions::getRoleId, role.getRoleId());
            });

            // 添加新的权限关联
            for (Integer permissionId : permissionIds) {
                AdminRolePermissions rolePermission = new AdminRolePermissions();
                rolePermission.setRoleId(role.getRoleId());
                rolePermission.setPermissionId(permissionId);
                adminRolePermissionsMapper.save(rolePermission);
            }
        }
    }

    /**
     * 删除角色
     * 实现步骤：
     * 1. 验证角色存在性
     * 2. 检查角色使用状态
     * 3. 删除角色及其关联数据
     *
     * 说明：
     * - 如果角色正在被管理员使用，则不允许删除
     * - 删除角色时会同时删除角色权限关联
     * - 使用事务确保数据一致性
     *
     * @param roleId 角色ID
     * @throws BaseException 当角色不存在或正在使用中时
     */
    @Override
    @Transactional
    public void deleteRole(Integer roleId) {
        // 检查角色是否存在
        if (!roleExists(roleId)) {
            throw new BaseException(MessageConstant.ROLE_NOT_FOUND);
        }

        // 检查是否有管理员正在使用该角色
        long adminCount = getAdminCountByRole(roleId);
        if (adminCount > 0) {
            throw new BaseException(MessageConstant.ROLE_IN_USE);
        }

        // 先删除角色权限关联
        adminRolePermissionsMapper.delete(where -> {
            where.eq(AdminRolePermissions::getRoleId, roleId);
        });

        // 删除角色
        adminRolesMapper.delete(where -> {
            where.eq(AdminRoles::getRoleId, roleId);
        });

    }

    /**
     * 获取角色的所有权限ID
     * 实现步骤：
     * 1. 查询角色权限关联表
     * 2. 提取权限ID列表
     *
     * @param roleId 角色ID
     * @return 该角色拥有的所有权限ID列表
     */
    @Override
    public List<Integer> getRolePermissions(Integer roleId) {
        List<AdminRolePermissions> permissions = adminRolePermissionsMapper.list(where -> {
            where.eq(AdminRolePermissions::getRoleId, roleId);
        });
        return permissions.stream()
                .map(AdminRolePermissions::getPermissionId)
                .collect(Collectors.toList());
    }

    /**
     * 移除管理员的角色
     * 实现步骤：
     * 1. 构建删除条件
     * 2. 执行删除操作
     *
     * 说明：
     * - 支持批量移除多个角色
     * - 如果指定的角色未分配给管理员，则忽略
     * - 使用事务确保数据一致性
     *
     * @param adminId 管理员ID
     * @param roleIds 要移除的角色ID列表
     */
    @Override
    @Transactional
    public void removeRolesFromAdmin(Integer adminId, List<Integer> roleIds) {
        adminRoleAssignmentsMapper.delete(where -> {
            where.eq(AdminRoleAssignments::getAdminId, adminId)
                .in(AdminRoleAssignments::getRoleId, roleIds);
        });
    }

    /**
     * 分页查询角色列表
     * 实现步骤：
     * 1. 构建查询条件
     * 2. 添加名称模糊查询（如果提供了名称）
     * 3. 执行分页查询
     * 4. 转换为VO对象并填充权限信息
     *
     * @param pager 分页参数
     * @param name 角色名称（可选）
     * @return 分页结果
     */
    @Override
    public Pager<AdminRoleVO> pageQuery(PageQueryDTO pager, String name) {
        // 构建基础查询
        Pager<AdminRoles> rolePager = QueryChain.of(adminRolesMapper)
                .ignoreNullValueInCondition(true)
                .ignoreEmptyInCondition(true)
                .trimStringInCondition(true)
                .like(AdminRoles::getRoleName, name)
                .paging(Pager.of(pager.getPage(),pager.getPageSize()));

        // 获取所有权限信息，用于后续填充权限名称
        List<AdminPermissions> allPermissions = QueryChain.of(adminPermissionsMapper).list();
        Map<Integer, String> permissionMap = allPermissions.stream()
            .collect(Collectors.toMap(
                AdminPermissions::getPermissionId,
                AdminPermissions::getPermissionName
            ));

        // 转换为VO对象
        List<AdminRoleVO> voList = new ArrayList<>();
        for (AdminRoles role : rolePager.getResults()) {
            AdminRoleVO vo = new AdminRoleVO();
            BeanUtils.copyProperties(role, vo);
            vo.setName(role.getRoleName());
            vo.setId(Long.valueOf(role.getRoleId()));

            // 获取角色的权限列表
            List<AdminRolePermissions> permissions = adminRolePermissionsMapper.list(where -> {
                where.eq(AdminRolePermissions::getRoleId, role.getRoleId());
            });

            // 转换权限信息
            if (permissions != null && !permissions.isEmpty()) {
                List<AdminRoleVO.PermissionVO> permissionVOs = permissions.stream()
                    .map(permission -> {
                        AdminRoleVO.PermissionVO permissionVO = new AdminRoleVO.PermissionVO();
                        permissionVO.setId(permission.getPermissionId().longValue());
                        permissionVO.setName(permissionMap.get(permission.getPermissionId()));
                        return permissionVO;
                    })
                    .collect(Collectors.toList());
                vo.setPermissions(permissionVOs);
            }

            voList.add(vo);
        }

        // 创建新的分页结果
        Pager<AdminRoleVO> result = new Pager<>();
        result.setResults(voList);
        result.setTotal(rolePager.getTotal());
        result.setSize(rolePager.getSize());

        return result;
    }

    /**
     * 检查角色是否存在
     * 实现步骤：
     * 1. 根据角色ID查询角色记录
     * 2. 判断查询结果是否为空
     *
     * @param roleId 角色ID
     * @return true-角色存在，false-角色不存在
     */
    @Override
    public boolean roleExists(Integer roleId) {
        return adminRolesMapper.get(where -> {
            where.eq(AdminRoles::getRoleId, roleId);
        }) != null;
    }

    /**
     * 获取使用某个角色的管理员数量
     * 实现步骤：
     * 1. 统计角色分配表中的记录数
     *
     * 说明：
     * - 用于角色删除前的检查
     * - 如果返回值大于0，表示角色正在使用中
     *
     * @param roleId 角色ID
     * @return 使用该角色的管理员数量
     */
    @Override
    public long getAdminCountByRole(Integer roleId) {
        return adminRoleAssignmentsMapper.count(where -> {
            where.eq(AdminRoleAssignments::getRoleId, roleId);
        });
    }
} 